package com.briup.jdbc;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.stream.Collectors;

/**
 * JDBC的工具类
 */
public class JdbcUtils {
    private static DataSource dataSource;
    private static Properties properties = new Properties();
    static {

        try {
            properties.load(JdbcUtils.class.getClassLoader().getResourceAsStream("com/briup/jdbc/druid.properties"));
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 数据库连接池获取链接对象
     * @return java.sql.Connection
     */
    public static Connection getDruidConnection(){
        Connection connection = null;
        try {
           connection  = dataSource.getConnection();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return connection;
    }

    /**
     * 普通方式获取连接对象
     * @return java.sql.Connection
     */
    public static Connection getConnection(){
        // 获取连接四要素
        String driver = properties.getProperty("driverClassName");
        String url = properties.getProperty("url");
        String user = properties.getProperty("username");
        String password = properties.getProperty("password");
        Connection connection = null;
        try {
            Class.forName(driver);
            connection = DriverManager.getConnection(url, user, password);
        } catch (ClassNotFoundException | SQLException e) {
            throw new RuntimeException(e);
        }
        return connection;
    }

    /**
     * 资源关闭
     * @param connection java.sql.Connection
     * @param statement java.sql.Statement
     * @param resultSet java.sql.ResultSet
     */
    public static void close(Connection connection, Statement statement, ResultSet resultSet) {
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 执行DDL语句
     * @param sql DDL
     */
    public static void executeDDL(String sql){
        int i = executeDML(sql);
    }

    /**
     * 执行DML语句
     * @param sql DML
     * @return int 返回受影响的行数
     */
    public static Integer executeDML(String sql){
        Connection connection = getDruidConnection();
        Statement statement = null;
        Integer i = null;
        try {
            statement = connection.createStatement();
            i = statement.executeUpdate(sql);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return i;
    }

    /**
     * 执行DQL语句
     * @param sql DQL
     * @return java.sql.ResultSet 结果集
     */
    public static ResultSet executeDQL(String sql){
        Connection connection = getDruidConnection();
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            statement = connection.createStatement();
            resultSet = statement.executeQuery(sql);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return resultSet;
    }

    public static <T> T executeDQLRetuenObject(String sql, Class<T> clazz){
        Connection connection = getDruidConnection();
        Statement statement = null;
        ResultSet resultSet = null;
        T t = null;
        try {
            statement = connection.createStatement();
            resultSet = statement.executeQuery(sql);
            t = clazz.getConstructor().newInstance();
            Method[] methods = clazz.getDeclaredMethods(); // 获取所有方法
            List<Method> setMethods = Arrays.stream(methods) // 筛选出set方法
                    .filter(method -> method.getName().startsWith("set") && method.getParameterCount() == 1)
                    .collect(Collectors.toList());
            while (resultSet.next()) {
                // 执行t里的所有set方法
                for (int i=0;i<= setMethods.size();i++) { // 遍历set方法并调用它们
                    try {
                        // 这个地方容易出错
                        setMethods.get(i).invoke(t, resultSet.getObject(i+1)); // 调用set方法，其中"newValue"是要设置的值，类型需要与参数匹配
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        return t;
    }
}
